#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
#include "pcb.c"

typedef struct queue {
        int size;
        PCBStr *head;
        PCBStr *tail;
} pcb_queue;


pcb_queue *ready_queue;

//returns 0 if process is done, else -1.
int check_process_done(int timer)
{
	if ((QUANTUM - timer) == ready_queue->head->next->next_step)
	{
		return 0;
	}
	else
	{
		return -1;
	}
}
int add_process_to_readyqeueue(ProcessStr *a_process)
{
	if (ready_queue == NULL) {
		return FALSE;
	}

	PCBStr* temp = malloc(sizeof(PCBStr));
	temp->pid = a_process;
	temp->next_step = temp->pid->no_steps;
	temp->state = 1; // initialised to ready; 0=running, 1=ready, 2=interrupted, 3=blocked
	temp->request_index = 0;
	temp->next = ready_queue->tail->prev;
	temp->prev = ready_queue->tail->prev->prev;
	temp->prev->next = temp;
	ready_queue->tail->prev->prev = temp;
	ready_queue->size++;

	return TRUE;

}

//head and tail are dummy pcb's
//idle process added to the queue. 
pcb_queue* create_ready_queue()
{
	pcb_queue* list = malloc(sizeof(pcb_queue));
	list->head = malloc(sizeof(PCBStr));
	ProcessStr *head_process = malloc(sizeof(ProcessStr));
        strcpy(head_process->name, "head");
        head_process->no_steps = QUANTUM;
        head_process->no_requests = 0;//this process does not make any requests
	list->head->pid = head_process;
	ProcessStr *tail_process = malloc(sizeof(ProcessStr));
        strcpy(tail_process->name, "tail");
        tail_process->no_steps = QUANTUM;
        tail_process->no_requests = 0;//this process does not make any requests
	list->tail = malloc(sizeof(PCBStr));
	list->tail->pid = tail_process;
	puts("Ready Queue created.\n");
	list->size = 0;
	list->head->prev = NULL;
	list->tail->next = NULL;
	ProcessStr *idle_process = malloc(sizeof(ProcessStr));
	strcpy(idle_process->name, "idle");
	idle_process->no_steps = QUANTUM;
	idle_process->no_requests = 0;//this process does not make any requests
	PCBStr* idle = malloc(sizeof(PCBStr));
	idle->pid = idle_process;
 	idle->next_step = idle->pid->no_steps;
	idle->state = 1;
	idle->next =  list->tail;
	idle->prev = list->head;
	list->head->next = idle;
	list->tail->prev = idle;
	list->size++;
	puts("Idle process added to queue.\n");
	ready_queue = list;
	return ready_queue;

}


void set_up_scheduler()
{
	ready_queue = create_ready_queue();
}

void get_next_process_running()
{
	ready_queue->head->next->state = 0; //the process at the front of the queue is running.
	printf("Process %s is now running.\n",  ready_queue->head->next->pid->name);
}

void scheduler_start()
{
	get_next_process_running();
}

void add_pcb_ready_queue(PCBStr *pcb)
{
 pcb->next =  ready_queue->tail->prev;
 pcb->prev =  ready_queue->tail->prev->prev;
 ready_queue->tail->prev->prev->next = pcb; 
 ready_queue->tail->prev->prev =  pcb;
 ready_queue->size++;

}

PCBStr *ready_queue_process_remove() {
	PCBStr *skipped;
	if (ready_queue == NULL || (ready_queue != NULL && ready_queue->size == 0)) {
		puts("Ready queue provided is NULL or empty, exiting...");
		exit(-1);
	}

	if( strcmp(ready_queue->head->next->pid->name, "idle") == 0 )
	{
                puts("Ready queue provided has only one process, idle process.");
		//will continue to run idle process, which is the only remaining process in the ready queue.
	}
	else
	{
		skipped = ready_queue->head->next;
		ready_queue->head->next = skipped->next;
		ready_queue->head->next->prev = ready_queue->head;
		skipped->next->prev = skipped->prev;
		ready_queue->size--;
		printf("Process %s removed from front of the ready queue.\n", skipped->pid->name);
	
	}
	return skipped;
}

